package com.aipsi.cws.common.util.DataUtil;

import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 *     自动生成数据库记录的小工具
 *     对象属性请使用包装类
 *     serialVersionUID名字不能变
 * </p>
 * @author 大忽悠
 * @create 2022/3/26 16:35
 */
public class DataRandomGeneratorUtil {
    /**
     * 生成随机数--以当前时间为随机数
     */
    private static Random random=new Random(System.currentTimeMillis());
    /**
     * string类型默认生成的长度
     */
    private static int stringLen=5;
    /**
     * int生成的最大长度
     */
    private static int INTMAX=Integer.MAX_VALUE;
    /**
     * 字段处理器
     */
    private static List<FiledProcessor> filedProcessors=new ArrayList<>();

    /**
     * 添加默认的字段处理器
     */
    static {
        //对被IgnoreFiled标注的字段忽略处理
        //对serialVersionUID标注的字段忽略处理
        filedProcessors.add((field,target) -> {
            if(field.isAnnotationPresent(IgnoreFiled.class)||field.getName().equals("serialVersionUID"))
            {
               return false;
            }
            return true;
        });
        //对字段范围进行判断
        filedProcessors.add((field,target) -> {
           if(field.isAnnotationPresent(FiledInfo.class))
           {
               FiledInfo annotation = field.getAnnotation(FiledInfo.class);
               //取出范围值,进行分析和判断,然后赋予随机值
               Class<?> type = field.getType();
               if(type.equals(Integer.class))
               {
                   DataTypeEnum dataTypeEnum = annotation.intLen();
                   autoWiredByDataType(dataTypeEnum,field,target);
               }else if(type.equals(String.class))
               {
                   int len = annotation.StringLen();
                   field.set(target, UUID.randomUUID().toString().substring(0,len));
               }
               return false;
           }
           return true;
        });
    }

    /**
     * <p>
     *     根据范围的不同,进行随机注入
     * </p>
     * @param dataTypeEnum 属性属于的数据库类型
     * @param field 字段
     */
    public static void autoWiredByDataType(DataTypeEnum dataTypeEnum,Field field,Object target) throws IllegalAccessException {
        if(dataTypeEnum.equals(DataTypeEnum.TINYINT))
        {
            field.set(target,random.nextInt(127));
        }
        else if(dataTypeEnum.equals(DataTypeEnum.SMALLINT))
        {
            field.set(target,random.nextInt(32767));
        }
        else if(dataTypeEnum.equals(DataTypeEnum.MEDIUMINT))
        {
            field.set(target,random.nextInt(8388607));
        }
        else if(dataTypeEnum.equals(DataTypeEnum.INT))
        {
            field.set(target,random.nextInt(2147483647));
        }
    }

    /**
     * @param pojoClass 对象类型
     * @param size  生成多少条记录
     */
   public static List randomGeneratorDatas(Class pojoClass, int size) throws InstantiationException, IllegalAccessException {
       List dataList=new ArrayList();
       for(int i=0;i<size;i++)
       {
           dataList.add(generatorOneRandomData(pojoClass));
       }
       return dataList;
   }

    /**
     * @param pojoClass 对象类型
     * @param size  生成多少条记录
     * @param specialFileds 需要被特殊照顾的属性---属性名和该属性名可以选择的值列表
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static List randomGeneratorDatas(Class pojoClass, int size, Map<String,List> specialFileds) throws InstantiationException, IllegalAccessException {
        List dataList=new ArrayList();
        for(int i=0;i<size;i++)
        {
            dataList.add(generatorOneRandomData(pojoClass,specialFileds));
        }
        return dataList;
    }

    /**
     * @param pojoClass 对象类型
     * @return 返回随机赋值完后的对象
     */
    private static Object generatorOneRandomData(Class pojoClass) throws InstantiationException, IllegalAccessException {
      return generatorOneRandomData(pojoClass,null);
    }


    /**
     * @param pojoClass 对象类型
     * @param specialFileds 需要被特殊照顾的字段
     * @return 返回被随机赋值的镀锡
     */
   private static Object generatorOneRandomData(Class pojoClass,Map<String,List> specialFileds) throws InstantiationException, IllegalAccessException {
       Object newInstance = pojoClass.newInstance();
       Field[] fields = pojoClass.getDeclaredFields();
       Set<String> keySet=null;
       if(specialFileds!=null){
          keySet= specialFileds.keySet();
       }
       for (int i = 0; i < fields.length; i++) {
           Field field=fields[i];
           field.setAccessible(true);
           //只要有一个处理器返回false,就将下面的字段改为true,表示忽略对当前字段的自动赋值处理
           boolean continueIf=false;
           for (int i1 = 0; i1 < filedProcessors.size(); i1++) {
               if(!filedProcessors.get(i1).process(field,newInstance))
               {
                   continueIf=true;
                  break;
               }
           }
           //是否要忽略对当前字段的处理
           if(continueIf)
           {
               continue;
           }
           //当前属性需要被特殊照顾
            if(keySet!=null&&keySet.contains(field.getName()))
           {
               //该属性可以选择的值列表---我们从里面随机取一个进行赋值即可
               List list = specialFileds.get(field.getName());
               autowiredRandomByList(field,newInstance,list);
               continue;
           }
           autowiredRandom(field,newInstance);
       }
       return newInstance;
   }

    /**
     * 对于指定属性，从指定值集合中选择一个值进行赋值
     */
    private static void autowiredRandomByList(Field field, Object target,List values) throws IllegalAccessException {
        field.set(target,values.get(random.nextInt(values.size())));
    }

    /**
     * @param field 需要被随机赋值的属性
     */
    private static void autowiredRandom(Field field,Object target) throws IllegalAccessException {
       Class<?> fieldType = field.getType();
       if(fieldType.equals(String.class))
       {
           field.set(target, UUID.randomUUID().toString().substring(0,stringLen));
       }
       else if(fieldType.equals(Integer.class))
       {
          field.set(target,random.nextInt(INTMAX));
       }
       else if(fieldType.equals(Boolean.class))
       {
           field.set(target,random.nextInt(2)==0?true:false);
       }else if(fieldType.equals(LocalDateTime.class))
       {
           //时间默认为当前时间---先设置为不随机
           field.set(target,LocalDateTime.now());
       }
       else if(fieldType.equals(Long.class))
       {
           field.set(target,random.nextLong());
       }
   }

    public static int getStringLen() {
        return stringLen;
    }

    public static void setStringLen(int stringLen) {
        DataRandomGeneratorUtil.stringLen = stringLen;
    }

    public static int getIntMax() {
        return INTMAX;
    }

    public static void setIntMax(int intMax) {
        DataRandomGeneratorUtil.INTMAX = intMax;
    }

    public static void addFiledProcessor(FiledProcessor filedProcessor)
    {
        filedProcessors.add(filedProcessor);
    }
}
